package com.zyd.shiro.business.interceptor;



import com.zyd.shiro.business.consts.SessionConst;
import com.zyd.shiro.business.entity.Data;
import com.zyd.shiro.business.entity.User;
import com.zyd.shiro.framework.object.AbstractDataDO;
import com.zyd.shiro.persistence.beans.SysData;
import com.zyd.shiro.util.SqlParserUtil;
import net.sf.jsqlparser.JSQLParserException;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.sql.Connection;
import java.sql.SQLOutput;
import java.util.Properties;


@Intercepts({
        @Signature(
                type = StatementHandler.class,
                method = "prepare",
                args = {
                        Connection.class,
                        Integer.class
                }
        )
})
@Component
public class MyBatisInterceptor implements Interceptor {
    public static final String CLASS_PATH = "com.zyd.shiro.persistence.beans.";

   /* @Resource
    private SysDataMapper sysDataMapper;*/

    //方法拦截
    @Override
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public Object intercept(Invocation invocation) throws Throwable {
        //拦截

        interceptor(invocation);

        return invocation.proceed();
    }

    //获取到拦截的对象，底层也是通过代理实现的，实际上是拿到一个目标代理对象
    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    //获取设置的阈值等参数
    @Override
    public void setProperties(Properties properties) {

    }

    private void interceptor(Invocation invocation) throws JSQLParserException, NoSuchFieldException, IllegalAccessException {

        System.out.println("###########"+invocation.getTarget());

        if(!(invocation.getTarget() instanceof RoutingStatementHandler)) {
            return;
        }


        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();

        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);


        BoundSql boundSql = statementHandler.getBoundSql();

        String sql = boundSql.getSql();

        if(sql.equals("SELECT LAST_INSERT_ID()")){
            return;
        }

        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");

        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        //增强sql代码块
        if ("SELECT".equals(sqlCommandType.toString())&&hasAbstractDataDO(strConvClass(mappedStatement.getId()))) {
            Session session =  SecurityUtils.getSubject().getSession();
            User user = (User) session.getAttribute(SessionConst.USER_SESSION_KEY);
            Data data = (Data) session.getAttribute(SessionConst.DATA_SESSION_KEY);
            if(null==user){
                return;
            }
            String roleStr = user.getUserType();
            if(roleStr.equals("USER")||roleStr.equals("ADMIN")){
                String mSql = SqlParserUtil
                        .addToWhere(sql,datafilter(data.getSysData(),user.getDept(),roleStr));
                //通过反射修改sql语句
                Field field = boundSql.getClass().getDeclaredField("sql");
                field.setAccessible(true);
                field.set(boundSql, mSql);
            }
        }
    }

    private static String datafilter(SysData sysData,Long deptId,String roleStr){

        if(roleStr.equals("USER")||sysData.getOrgs()==null){
           return " dept="+ deptId+" ";
        }
        if(sysData.getDepts()==null){
            return " org IN ("+ sysData.getOrgs()+" )";
        }
        String where = " dept IN ("+ sysData.getDepts()+" ) ";
        if(sysData.getLocations()!=null){
            where += " AND location IN ("+sysData.getLocations()+") ";
        }
        return where;
    }

    private static boolean hasAbstractDataDO(Class cls){
        if(null == cls){
            return false;
        }
       return AbstractDataDO.class.isAssignableFrom(cls);
    }

    /**
     * com.zyd.shiro.persistence.mapper.SysResourceMapper.listUrlAndPermission
     * @param mapperPath
     * @return
     */
    private static Class strConvClass(String mapperPath)  {
        if(!mapperPath.contains("Pak")){
            return null;
        }
        String bagPath = mapperPath.substring(0,mapperPath.lastIndexOf("."));
        String className = bagPath.substring(bagPath.lastIndexOf(".")+1,bagPath.length()).replace("Mapper","");
        Class cls = null;
        try {
            cls = Class.forName(CLASS_PATH+className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            return null;

        }
        return cls;
    }







}
